<?php

namespace plugin\voice\app\controller;

use support\Request;
use support\Response;
use Webman\Medoo\Medoo as db;
use Yansongda\Pay\Pay;

class PayController{
    
    protected $noNeedLogin = ['index','notify','getUserInfo'];
    
    public function notify(Request $request){
        $content                = $request->rawBody();
        $xml                    = simplexml_load_string(trim($content), "SimpleXMLElement", LIBXML_NOCDATA);
        $return_code            = $xml->return_code;
        $data['appid']          = trim($xml->appid);
        $data['attach']         = trim($xml->attach);
        $data['bank_type']      = trim($xml->bank_type);
        $data['cash_fee']       = trim($xml->cash_fee);
        $data['mch_id']         = trim($xml->mch_id);
        $data['openid']         = trim($xml->openid);
        $data['out_trade_no']   = trim($xml->out_trade_no);
        $data['result_code']    = trim($xml->result_code);
        $data['sub_mch_id']     = trim($xml->sub_mch_id);
        $data['time_end']       = trim($xml->time_end);
        $data['total_fee']      = trim($xml->total_fee);
        $data['trade_type']     = trim($xml->trade_type);
        $data['transaction_id'] = trim($xml->transaction_id);
        db::insert('voice_log', [
            'name'         => '支付回调', 
            'content'      => json_encode($request->rawBody()),
            'out_trade_no' => $data['out_trade_no']
        ]);
        if($return_code=='SUCCESS'){
            $checkOrder = db::get('voice_orders','*',['out_trade_no' => $data['out_trade_no'],'status' => 1]);
            if($checkOrder){
                $data['status'] = 2;
                db::update('voice_orders', $data,['id' => $checkOrder['id']]);
                $checkUserInfo = db::get('voice_users','*',['id' => $checkOrder['user_id']]);
                if($checkUserInfo){
                    $planInfo = db::get('voice_plans','*',['id' => $checkOrder['plan_id']]);
                    // 更新用户问答数
                    db::update('voice_users',[
                        'field1[+]' => $planInfo['field1'],
                        'field2[+]' => $planInfo['field2'],
                        'field3[+]' => $planInfo['field3'],
                        'field4[+]' => $planInfo['field4'],
                        'field5[+]' => $planInfo['field5'],
                        'field6[+]' => $planInfo['field6'],
                    ],['id' => $checkUserInfo['id']]);
                    // 记录更新
                    $updateData               = [];
                    $updateData['user_id']    = $checkUserInfo['id'];
                    $updateData['old_field1'] = $checkUserInfo['field1'];
                    $updateData['old_field2'] = $checkUserInfo['field2'];
                    $updateData['old_field3'] = $checkUserInfo['field3'];
                    $updateData['old_field4'] = $checkUserInfo['field4'];
                    $updateData['old_field5'] = $checkUserInfo['field5'];
                    $updateData['old_field6'] = $checkUserInfo['field6'];
                    $updateData['field1']     = $checkUserInfo['field1'] + $planInfo['field1'];
                    $updateData['field2']     = $checkUserInfo['field2'] + $planInfo['field2'];
                    $updateData['field3']     = $checkUserInfo['field3'] + $planInfo['field3'];
                    $updateData['field4']     = $checkUserInfo['field4'] + $planInfo['field4'];
                    $updateData['field5']     = $checkUserInfo['field5'] + $planInfo['field5'];
                    $updateData['field6']     = $checkUserInfo['field6'] + $planInfo['field6'];
                    $updateData['remark']     = $data['out_trade_no'];
                    db::insert('voice_users_log',$updateData);
                }
            }
        }
        return '<xml>
              <return_code><![CDATA[SUCCESS]]></return_code>
              <return_msg><![CDATA[OK]]></return_msg>
            </xml>';
    }
    
    public function index(Request $request){
        $openid                      = $request->post('openid');
        $plan                        = db::get('voice_plans','*',['id' => $request->post('id')]);
        if(!$plan){
            return json([
                'code' => -1,
                'msg'  => '当前商品不存在'
            ]);
        }
        $setting                     = db::get('voice_settings','*');
        if(!$setting){
            return json([
                'code' => -1,
                'msg'  => '当前支付未开启'
            ]);
        }
        $postData                     = [];
        $postData['openid']           = $openid;
        $postData['sub_mch_id']       = $setting['sub_mch_id'];
        $postData['title']            = $plan['title'];
        $postData['price']            = $plan['price'];
        $postData['out_trade_no']     = date('YmdHis').mt_rand(100000,999999);
        $postData['spbill_create_ip'] = $request->getRealIp();
        $postData['notify_url']       = $setting['notify_host']."/app/voice/pay/notify";
        $unifiedorder_url             = $setting['unifiedorder_host']."/partner/pay";
        $result                       = self::posthtmlstr($unifiedorder_url, $postData, 1, false);
        if($result['code'] == 200){
            // 写入订单
            $orderData                 = [];
            $orderData['openid2']      = $openid;
            $orderData['plan_id']      = $request->post('id');
            $orderData['user_id']      = $request->userInfo['id'];
            $orderData['title']        = $plan['title'];
            $orderData['out_trade_no'] = $postData['out_trade_no'];
            $orderData['price']        = $plan['price'];
            db::insert('voice_orders', $orderData);
            return json([
    		    'code' => 200, 
    		    'msg'  => 'ok', 
    		    'data' => $result
    		]);
        }else{
            return json([
    		    'code' => -1, 
    		    'msg'  => '支付通道维护中', 
    		]);
        }
		
    }
    
    function array2xml($arr, $level = 1) {
    	$s = $level == 1 ? "<xml>" : '';
    	foreach ($arr as $tagname => $value) {
    		if (is_numeric($tagname)) {
    			$tagname = $value['TagName'];
    			unset($value['TagName']);
    		}
    		if (!is_array($value)) {
    			$s .= "<{$tagname}>" . (!is_numeric($value) ? '<![CDATA[' : '') . $value . (!is_numeric($value) ? ']]>' : '') . "</{$tagname}>";
    		} else {
    			$s .= "<{$tagname}>" . array2xml($value, $level + 1) . "</{$tagname}>";
    		}
    	}
    	$s = preg_replace("/([\x01-\x08\x0b-\x0c\x0e-\x1f])+/", ' ', $s);
    	return $level == 1 ? $s . "</xml>" : $s;
    }
    
    public function posthtmlstr($url = '', $params = false, $ispost = 1 ,$header = false, $proxyServer =false){
        $httpInfo = array();
        $curl = curl_init();
        curl_setopt($curl,CURLOPT_HTTP_VERSION,CURL_HTTP_VERSION_1_1);
        curl_setopt($curl,CURLOPT_RETURNTRANSFER,true);
        curl_setopt($curl, CURLOPT_FOLLOWLOCATION,true);
        if($header) curl_setopt($curl, CURLOPT_HTTPHEADER, $header);
        if($proxyServer){
            curl_setopt($curl, CURLOPT_HTTPPROXYTUNNEL, false);
            curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
            curl_setopt($curl, CURLOPT_PROXYTYPE, 5); //sock5
            curl_setopt($curl, CURLOPT_PROXY, $proxyServer);
            curl_setopt($curl, CURLOPT_PROXYAUTH, CURLAUTH_BASIC);
            curl_setopt($curl, CURLOPT_USERAGENT, "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 2.0.50727;)");
            curl_setopt($curl, CURLOPT_CONNECTTIMEOUT, 3);
            curl_setopt($curl, CURLOPT_TIMEOUT, 5);
            curl_setopt($curl, CURLOPT_HEADER, true);
            curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
        }
        if($ispost){
            curl_setopt($curl,CURLOPT_POST,true);
            curl_setopt($curl,CURLOPT_POSTFIELDS,$params);
            curl_setopt($curl,CURLOPT_URL, $url);
        }else{
            if($params){
             curl_setopt($curl,CURLOPT_URL,$url.'?'.$params);
            }else{
             curl_setopt($curl,CURLOPT_URL,$url);
            }
        }
        
        $httpCode = curl_getinfo($curl,CURLINFO_HTTP_CODE);
        $tmpInfo = json_decode(curl_exec( $curl ),true);
        if ($tmpInfo === FALSE){
            return false;
        }
        $httpCode = curl_getinfo($curl,CURLINFO_HTTP_CODE);
        $httpInfo = array_merge($httpInfo,curl_getinfo($curl));
        curl_close($curl);
        return $tmpInfo;
    }
    
    public static function ihttp_post($url, $data) {
    	$headers = array('Content-Type' => 'application/x-www-form-urlencoded');
    	return self::ihttp_request($url, $data, $headers);
    }
    
    public static function ihttp_request($url, $post = '', $extra = array(), $timeout = 60) {
		if (function_exists('curl_init') && function_exists('curl_exec') && $timeout > 0) {
    		$ch = self::ihttp_build_curl($url, $post, $extra, $timeout);
    		if (self::is_error($ch)) {
    			return $ch;
    		}
    		
    		$data = curl_exec($ch);
    		$status = curl_getinfo($ch);
    		$errno = curl_errno($ch);
    		$error = curl_error($ch);
    		curl_close($ch);
    		if ($errno || empty($data)) {
    			return self::error($errno, $error);
    		} else {
    			return self::ihttp_response_parse($data);
    		}
    	}
    	$urlset = self::ihttp_parse_url($url, true);
    	if (!empty($urlset['ip'])) {
    		$urlset['host'] = $urlset['ip'];
    	}
    	$body = self::ihttp_build_httpbody($url, $post, $extra);
    
    	if ($urlset['scheme'] == 'https') {
    		$fp = self::ihttp_socketopen('ssl://' . $urlset['host'], $urlset['port'], $errno, $error);
    	} else {
    		$fp = self::ihttp_socketopen($urlset['host'], $urlset['port'], $errno, $error);
    	}
    	stream_set_blocking($fp, $timeout > 0 ? true : false);
    	stream_set_timeout($fp, ini_get('default_socket_timeout'));
    	if (!$fp) {
    		return self::error(1, $error);
    	} else {
    		fwrite($fp, $body);
    		$content = '';
    		if($timeout > 0) {
    			while (!feof($fp)) {
    				$content .= fgets($fp, 512);
    			}
    		}
    		fclose($fp);
    		return self::ihttp_response_parse($content, true);
    	}
    }
    
    public static function ihttp_response_parse($data, $chunked = false) {
    	$rlt = array();
    	$headermeta = explode('HTTP/', $data);
    	if (count($headermeta) > 2) {
    		$data = 'HTTP/' . array_pop($headermeta);
    	}
    	$pos = strpos($data, "\r\n\r\n");
    	$split1[0] = substr($data, 0, $pos);
    	$split1[1] = substr($data, $pos + 4, strlen($data));
    
    	$split2 = explode("\r\n", $split1[0], 2);
    	preg_match('/^(\S+) (\S+) (.*)$/', $split2[0], $matches);
    	$rlt['code'] = !empty($matches[2]) ? $matches[2] : 200;
    	$rlt['status'] = !empty($matches[3]) ? $matches[3] : 'OK';
    	$rlt['responseline'] = !empty($split2[0]) ? $split2[0] : '';
    	$header = explode("\r\n", $split2[1]);
    	$isgzip = false;
    	$ischunk = false;
    	foreach ($header as $v) {
    		$pos = strpos($v, ':');
    		$key = substr($v, 0, $pos);
    		$value = trim(substr($v, $pos + 1));
    		if (isset($rlt['headers'][$key]) && is_array($rlt['headers'][$key])) {
    			$rlt['headers'][$key][] = $value;
    		} elseif (!empty($rlt['headers'][$key])) {
    			$temp = $rlt['headers'][$key];
    			unset($rlt['headers'][$key]);
    			$rlt['headers'][$key][] = $temp;
    			$rlt['headers'][$key][] = $value;
    		} else {
    			$rlt['headers'][$key] = $value;
    		}
    		if(!$isgzip && strtolower($key) == 'content-encoding' && strtolower($value) == 'gzip') {
    			$isgzip = true;
    		}
    		if(!$ischunk && strtolower($key) == 'transfer-encoding' && strtolower($value) == 'chunked') {
    			$ischunk = true;
    		}
    	}
    	if($chunked && $ischunk) {
    		$rlt['content'] = ihttp_response_parse_unchunk($split1[1]);
    	} else {
    		$rlt['content'] = $split1[1];
    	}
    	if($isgzip && function_exists('gzdecode')) {
    		$rlt['content'] = gzdecode($rlt['content']);
    	}
    
    	$rlt['meta'] = $data;
    	if($rlt['code'] == '100') {
    		return ihttp_response_parse($rlt['content']);
    	}
    	return $rlt;
    }
    
    public static function ihttp_socketopen($hostname, $port = 80, &$errno = null, &$errstr = null, $timeout = 15) {
    	$fp = '';
    	if(function_exists('fsockopen')) {
    		$fp = @fsockopen($hostname, $port, $errno, $errstr, $timeout);
    	} elseif(function_exists('pfsockopen')) {
    		$fp = @pfsockopen($hostname, $port, $errno, $errstr, $timeout);
    	} elseif(function_exists('stream_socket_client')) {
    		$fp = @stream_socket_client($hostname.':'.$port, $errno, $errstr, $timeout);
    	}
    	return $fp;
    }
    
    public static function is_error($data) {
    	if (empty($data) || !is_array($data) || !array_key_exists('errno', $data) || (array_key_exists('errno', $data) && $data['errno'] == 0)) {
    		return false;
    	} else {
    		return true;
    	}
    }
    public static function ihttp_build_curl($url, $post, $extra, $timeout) {
    	if (!function_exists('curl_init') || !function_exists('curl_exec')) {
    		return self::error(1, 'curl扩展未开启');
    	}
    
    	$urlset = self::ihttp_parse_url($url);
    	if (self::is_error($urlset)) {
    		return $urlset;
    	}
    
    	if (!empty($urlset['ip'])) {
    		$extra['ip'] = $urlset['ip'];
    	}
    
    	$ch = curl_init();
    	if (!empty($extra['ip'])) {
    		$extra['Host'] = $urlset['host'];
    		$urlset['host'] = $extra['ip'];
    		unset($extra['ip']);
    	}
    	curl_setopt($ch, CURLOPT_URL, $urlset['scheme'] . '://' . $urlset['host'] . (isset($urlset['port']) && $urlset['port'] == '80' || empty($urlset['port']) ? '' : ':' . $urlset['port']) . $urlset['path'] . isset($urlset['query'])?:'');
    	curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
    	@curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
    	curl_setopt($ch, CURLOPT_HEADER, 1);
    	@curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
    	if ($post) {
    		if (is_array($post)) {
    			$filepost = false;
				foreach ($post as $name => &$value) {
    				if (version_compare(phpversion(), '5.5') >= 0 && is_string($value) && substr($value, 0, 1) == '@') {
    					$post[$name] = new CURLFile(ltrim($value, '@'));
    				}
    				if ((is_string($value) && substr($value, 0, 1) == '@') || (class_exists('CURLFile') && $value instanceof CURLFile)) {
    					$filepost = true;
    				}
    			}
    			if (!$filepost) {
    				$post = http_build_query($post);
    			}
    		}
    		curl_setopt($ch, CURLOPT_POST, 1);
    		curl_setopt($ch, CURLOPT_POSTFIELDS, $post);
    	}
    	if (!empty($GLOBALS['_W']['config']['setting']['proxy'])) {
    		$urls = parse_url($GLOBALS['_W']['config']['setting']['proxy']['host']);
    		if (!empty($urls['host'])) {
    			curl_setopt($ch, CURLOPT_PROXY, "{$urls['host']}:{$urls['port']}");
    			$proxytype = 'CURLPROXY_' . strtoupper($urls['scheme']);
    			if (!empty($urls['scheme']) && defined($proxytype)) {
    				curl_setopt($ch, CURLOPT_PROXYTYPE, constant($proxytype));
    			} else {
    				curl_setopt($ch, CURLOPT_PROXYTYPE, CURLPROXY_HTTP);
    				curl_setopt($ch, CURLOPT_HTTPPROXYTUNNEL, 1);
    			}
    			if (!empty($GLOBALS['_W']['config']['setting']['proxy']['auth'])) {
    				curl_setopt($ch, CURLOPT_PROXYUSERPWD, $GLOBALS['_W']['config']['setting']['proxy']['auth']);
    			}
    		}
    	}
    	curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $timeout);
    	curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
    	curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
    	curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
    	curl_setopt($ch, CURLOPT_SSLVERSION, 1);
    	if (defined('CURL_SSLVERSION_TLSv1')) {
    		curl_setopt($ch, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1);
    	}
    	curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:9.0.1) Gecko/20100101 Firefox/9.0.1');
    	if (!empty($extra) && is_array($extra)) {
    		$headers = array();
    		foreach ($extra as $opt => $value) {
    			if (self::strexists($opt, 'CURLOPT_')) {
    				curl_setopt($ch, constant($opt), $value);
    			} elseif (is_numeric($opt)) {
    				curl_setopt($ch, $opt, $value);
    			} else {
    				$headers[] = "{$opt}: {$value}";
    			}
    		}
    		if (!empty($headers)) {
    			curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
    		}
    	}
    	return $ch;
    }
    
    public static function ihttp_parse_url($url, $set_default_port = false) {
    	if (empty($url)) {
    		return self::error(1);
    	}
    	$urlset = parse_url($url);
    	if (!empty($urlset['scheme']) && !in_array($urlset['scheme'], array('http', 'https'))) {
    		return error(1, '只能使用 http 及 https 协议');
    	}
    	if (empty($urlset['path'])) {
    		$urlset['path'] = '/';
    	}
    	if (!empty($urlset['query'])) {
    		$urlset['query'] = "?{$urlset['query']}";
    	}
    	if (self::strexists($url, 'https://') && !extension_loaded('openssl')) {
    		if (!extension_loaded("openssl")) {
    			return self::error(1,'请开启您PHP环境的openssl', '');
    		}
    	}
    	if (empty($urlset['host'])) {
    		$current_url = parse_url("https://api.youqianpay.com/");
    		$urlset['host'] = $current_url['host'];
    		$urlset['scheme'] = $current_url['scheme'];
    		$urlset['path'] = $current_url['path'] . 'web/' . str_replace('./', '', $urlset['path']);
    		$urlset['ip'] = '127.0.0.1';
    	} else if (! self::ihttp_allow_host($urlset['host'])){
    		return self::error(1, 'host 非法');
    	}
    
    	if ($set_default_port && empty($urlset['port'])) {
    		$urlset['port'] = $urlset['scheme'] == 'https' ? '443' : '80';
    	}
    	return $urlset;
    }
    
    public static function strexists($string, $find) {
    	return !(strpos($string, $find) === FALSE);
    }
    
    public static function ihttp_allow_host($host) {
    	global $_W;
    	if (self::strexists($host, '@')) {
    		return false;
    	}
    	$pattern = "/^(10|172|192|127)/";
    	if (preg_match($pattern, $host) && isset($_W['setting']['ip_white_list'])) {
    		$ip_white_list = $_W['setting']['ip_white_list'];
    		if ($ip_white_list && isset($ip_white_list[$host]) && !$ip_white_list[$host]['status']) {
    			return false;
    		}
    	}
    	return true;
    }
    
    
}
